﻿/* HEADER
 * ------
 * © 2009 by Salomon Zwecker 
 * modified by:
 * - 
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Shapes.Geometry;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Shapes.Misc.Appearance
{
    /// <summary>
    /// A Brush is used to Draw Borders of Drawings or Shapes.
    /// </summary>
    public class Brush
    {
        static Brush _StandardBrush;
        /// <summary>
        /// A Brush which is used, when no Brush is defined for drawing
        /// </summary>
        public static Brush StandardBrush
        {
            get
            {
                if (_StandardBrush == null)
                {
                    _StandardBrush = CreateFallOffBrush(1, 1);
                }

                return _StandardBrush;
            }
            set { _StandardBrush = value; }
        }

        /// <summary>
        /// Creates a new brush and adds a FallOff to it.
        /// </summary>
        /// <param name="radius">The radius of the brush tip.</param>
        /// <param name="fallOff">The FallOff defines, what distance at the outline of the brush tip is used to fade out into full transparency.</param>
        /// <returns>the created brush</returns>
        public static Brush CreateFallOffBrush(float radius, float fallOff)
        {
            Brush b = new Brush(radius);
            b.AddMask(new BrushMaskFallOff(fallOff));
            return b;
        }
        /// <summary>
        /// Creates a new brush and adds a FallOff to it.
        /// </summary>
        /// <param name="radius">The radius of the brush tip.</param>
        /// <param name="fallOff">The FallOff defines, what distance at the outline of the brush tip is used to fade out into full transparency.</param>
        /// <param name="color">the color of the brush</param>
        /// <returns>the created brush</returns>
        public static Brush CreateFallOffBrush(float radius, float fallOff, Color color)
        {
            Brush b = new Brush(radius, color);
            b.AddMask(new BrushMaskFallOff(fallOff));
            return b;
        }

        float _Radius;
        Color _Color;
        /// <summary>
        /// The radius of the brush tip
        /// </summary>
        public float Radius { get { return _Radius; } set { _Radius = value; } }
        /// <summary>
        /// The diameter is the whole size of the brush tip. It is 2 * radius.
        /// </summary>
        public float Diameter { get { return 2 * _Radius; } }


        private readonly List<BrushMask> _Masks = new List<BrushMask>();

        /// <summary>
        /// The Color of the Brush
        /// </summary>
        public Color Color { get { return _Color; } set { _Color = value; } }

        /// <summary>
        /// Creates a new Brush to draw ShapeBorders with
        /// </summary>
        /// <param name="radius">the radius in pixels of the brush tip</param>
        public Brush(float radius)
        {
            _Color = Color.White;
            _Radius = radius;
        }

        /// <summary>
        /// Creates a new Brush to draw ShapeBorders with
        /// </summary>
        /// <param name="radius">the radius in pixels of the brush tip</param>
        /// <param name="color">the color of the brush</param>
        public Brush(float radius, Color color)
        {
            _Color = color;
            _Radius = radius;
        }

        /// <summary>
        /// Adds a mask. A mask inherits BrushMask. It is possible to use more than one mask.
        /// </summary>
        /// <param name="mask">The mask to add.</param>
        public void AddMask(BrushMask mask)
        {
            _Masks.Add(mask);
        }

        internal Color GetColorAt(Drawing drawing, ref Vector2 localPosition)
        {
            float distanceToCenter = drawing.GetDistanceToEdge(ref localPosition);

            if (distanceToCenter <= Radius)
            {
                float value = 1f;
                float? t = null;
                foreach (BrushMask mask in _Masks)
                {
                    value *= mask.GetVisibilityValue(this, drawing, ref localPosition, ref distanceToCenter, ref t);
                }

#if XNA4
                return _Color * value;
#else
                return new Color(_Color, value);
#endif
            }
#if XNA4
            return Color.Transparent;
#else
            return Color.TransparentBlack;
#endif
        }

        /// <summary>
        /// Gets the offset for textures generated with this brush. Use (MyShape.Position - MyBrush.GetTextureOffset) to place the texture correct.
        /// </summary>
        /// <returns>the offset vector (positive values)</returns>
        public Vector2 GetTextureOffset()
        {
            Vector2 scale = Vector2.One;
            foreach (BrushMask mask in _Masks)
            {
                mask.ModifyScaleFactor(ref scale);
            }

            return new Vector2(_Radius * scale.X, _Radius * scale.Y);
        }
    }
}
